package com.hcloud.baselib.repo

import android.util.Log
import com.hcloud.baselib.common.StateLiveData
import com.hcloud.baselib.http.DataState
import com.hcloud.baselib.http.Res
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*

open class BaseRepo {

    companion object {
        private const val TAG = "BaseRepository"
    }

    /**
     * 方式二：结合Flow请求数据。
     * 根据Flow的不同请求状态，如onStart、onEmpty、onCompletion等设置Res.dataState状态值，
     * 最后通过stateLiveData分发给UI层。
     *
     * @param block api的请求方法
     * @param stateLiveData 每个请求传入相应的LiveData，主要负责网络状态的监听
     */
    suspend fun <T : Any> executeReqWithFlow(
        block: suspend () -> Res<T>,
        stateLiveData: StateLiveData<T>
    ) {
        var Res = Res<T>()
        flow {
            val respResult = block.invoke()
            Res = respResult
            Log.d(TAG, "executeReqWithFlow: $Res")
            Res.dataState = DataState.STATE_SUCCESS
            stateLiveData.postValue(Res)
            emit(respResult)
        }
            .flowOn(Dispatchers.IO)
            .onStart {
                Log.d(TAG, "executeReqWithFlow:onStart")
                Res.dataState = DataState.STATE_LOADING
                stateLiveData.postValue(Res)
            }
            .onEmpty {
                Log.d(TAG, "executeReqWithFlow:onEmpty")
                Res.dataState = DataState.STATE_EMPTY
                stateLiveData.postValue(Res)
            }
            .catch { exception ->
                run {
                    Log.d(TAG, "executeReqWithFlow:code  ${Res.code}")
                    exception.printStackTrace()
                    Res.dataState = DataState.STATE_ERROR
                    Res.error = exception
                    stateLiveData.postValue(Res)
                }
            }
            .collect {
                Log.d(TAG, "executeReqWithFlow: collect")
                stateLiveData.postValue(Res)
            }


    }

    /**
     * 方式一
     * repo 请求数据的公共方法，
     * 在不同状态下先设置 Res.dataState的值，最后将dataState 的状态通知给UI
     * @param block api的请求方法
     * @param stateLiveData 每个请求传入相应的LiveData，主要负责网络状态的监听
     */
    suspend fun <T : Any> executeResp(
        block: suspend () -> Res<T>,
        stateLiveData: StateLiveData<T>
    ) {
        var Res = Res<T>()
        try {
            Res.dataState = DataState.STATE_LOADING
            //开始请求数据
            val invoke = block.invoke()
            //将结果复制给Res
            Res = invoke
            if (Res.code == "0") {
                //请求成功，判断数据是否为空，
                //因为数据有多种类型，需要自己设置类型进行判断
                if (Res.data == null || Res.data is List<*> && (Res.data as List<*>).size == 0) {
                    //TODO: 数据为空,结构变化时需要修改判空条件
                    Res.dataState = DataState.STATE_EMPTY
                } else {
                    //请求成功并且数据为空的情况下，为STATE_SUCCESS
                    Res.dataState = DataState.STATE_SUCCESS
                }

            } else {
                //服务器请求错误
                Res.dataState = DataState.STATE_FAILED
            }
        } catch (e: Exception) {
            //非后台返回错误，捕获到的异常
            Res.dataState = DataState.STATE_ERROR
            Res.error = e
        } finally {
            stateLiveData.postValue(Res)
        }
    }


    /**
     * @deprecated Use {@link executeResp} instead.
     */
//    suspend fun <T : Any> executeResp(
//        resp: Res<T>,
//        successBlock: (suspend CoroutineScope.() -> Unit)? = null,
//        errorBlock: (suspend CoroutineScope.() -> Unit)? = null
//    ): ResState<T> {
//        return coroutineScope {
//            if (resp.errorCode == 0) {
//                successBlock?.let { it() }
//                ResState.Success(resp.data!!)
//            } else {
//                Log.d(TAG, "executeResp: error")
//                errorBlock?.let { it() }
//                ResState.Error(IOException(resp.errorMsg))
//            }
//        }
//    }
}